// ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 
//============================================================================
//  File:       IpcClientChannel.cs 
//  Author:   [....]@Microsoft.Com 
//  Summary:    Implements a channel that transmits method calls over Ipc.
// 
//=========================================================================

using System;
using System.Collections; 
using System.IO;
using System.Runtime.Remoting; 
using System.Runtime.Remoting.Channels; 
using System.Runtime.Remoting.Messaging;
using System.Runtime.InteropServices; 
using System.Security.Principal;
using System.Threading;
using System.Text;
using System.Globalization; 
using System.Security.Permissions;
 
 
namespace System.Runtime.Remoting.Channels.Ipc
{ 
    internal delegate IClientChannelSinkStack AsyncMessageDelegate(IMessage msg,
                                                               ITransportHeaders requestHeaders, Stream requestStream,
                                                               out ITransportHeaders responseHeaders, out Stream responseStream,
                                                               IClientChannelSinkStack sinkStack); 

    public class IpcClientChannel : IChannelSender, ISecurableChannel 
    { 
        private int    _channelPriority = 1;  // channel priority
        private String _channelName = "ipc client"; // channel name 
        private bool _secure = false; // default is unsecure
        private IDictionary _prop = null;

        private IClientChannelSinkProvider _sinkProvider = null; // sink chain provider 

 
        public IpcClientChannel() 
        {
            SetupChannel(); 
        } // IpcClientChannel


        public IpcClientChannel(String name, IClientChannelSinkProvider sinkProvider) 
        {
            _channelName = name; 
            _sinkProvider = sinkProvider; 

            SetupChannel(); 
        }


        // constructor used by config file 
        public IpcClientChannel(IDictionary properties, IClientChannelSinkProvider sinkProvider)
        { 
            if (properties != null) 
            {
                _prop = properties; 
                foreach (DictionaryEntry entry in properties)
                {
                    switch ((String)entry.Key)
                    { 
                    case "name": _channelName = (String)entry.Value; break;
                    case "priority": _channelPriority = Convert.ToInt32(entry.Value, CultureInfo.InvariantCulture); break; 
                    case "secure": _secure = Convert.ToBoolean(entry.Value, CultureInfo.InvariantCulture); break; 
                    default:
                         break; 
                    }
                }
            }
 
            _sinkProvider = sinkProvider;
 
            SetupChannel(); 
        } // IpcClientChannel
 

        private void SetupChannel()
        {
            if (_sinkProvider != null) 
            {
                CoreChannel.AppendProviderToClientProviderChain( 
                    _sinkProvider, new IpcClientTransportSinkProvider(_prop)); 
            }
            else 
                _sinkProvider = CreateDefaultClientProviderChain();
        } // SetupChannel

 
        //
        // ISecurableChannel implementation 
        // 
        public bool IsSecured
        { 
            [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure, Infrastructure=true)]
            get { return _secure; }
            [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure, Infrastructure=true)]
            set { _secure = value; } 
        }
 
        // 
        // IChannel implementation
        // 

        public int ChannelPriority
        {
            [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure, Infrastructure=true)] 
            get { return _channelPriority; }
        } 
 
        public String ChannelName
        { 
            [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure, Infrastructure=true)]
            get { return _channelName; }
        }
 
        // returns channelURI and places object uri into out parameter
        [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure, Infrastructure=true)] 
        public String Parse(String url, out String objectURI) 
        {
            return IpcChannelHelper.ParseURL(url, out objectURI); 
        } // Parse

        //
        // end of IChannel implementation 
        //
 
 

        // 
        // IChannelSender implementation
        //

        [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure, Infrastructure=true)] 
        public virtual IMessageSink CreateMessageSink(String url, Object remoteChannelData, out String objectURI)
        { 
            // Set the out parameters 
            objectURI = null;
            String channelURI = null; 


            if (url != null) // Is this a well known object?
            { 
                // Parse returns null if this is not one of our url's
                channelURI = Parse(url, out objectURI); 
            } 
            else // determine if we want to connect based on the channel data
            { 
                if (remoteChannelData != null)
                {
                    if (remoteChannelData is IChannelDataStore)
                    { 
                        IChannelDataStore cds = (IChannelDataStore)remoteChannelData;
 
                        // see if this is an Ipc uri 
                        String simpleChannelUri = Parse(cds.ChannelUris[0], out objectURI);
                        if (simpleChannelUri != null) 
                            channelURI = cds.ChannelUris[0];
                    }
                }
            } 

            if (null != channelURI) 
            { 
                if (url == null)
                    url = channelURI; 

                IClientChannelSink sink = _sinkProvider.CreateSink(this, url, remoteChannelData);

                // return sink after making sure that it implements IMessageSink 
                IMessageSink msgSink = sink as IMessageSink;
                if ((sink != null) && (msgSink == null)) 
                { 
                    throw new RemotingException(
                        CoreChannel.GetResourceString( 
                            "Remoting_Channels_ChannelSinkNotMsgSink"));
                }

                return msgSink; 
            }
 
            return null; 
        } // CreateMessageSink
 

        //
        // end of IChannelSender implementation
        // 

        private IClientChannelSinkProvider CreateDefaultClientProviderChain() 
        { 
            IClientChannelSinkProvider chain = new BinaryClientFormatterSinkProvider();
            IClientChannelSinkProvider sink = chain; 

            sink.Next = new IpcClientTransportSinkProvider( _prop);

            return chain; 
        } // CreateDefaultClientProviderChain
 
    } // class IpcClientChannel 

 


    internal class IpcClientTransportSinkProvider : IClientChannelSinkProvider
    { 
        IDictionary _prop = null;
        internal IpcClientTransportSinkProvider(IDictionary properties ) 
        { 
            _prop = properties;
        } 

        public IClientChannelSink CreateSink(IChannelSender channel, String url,
                                             Object remoteChannelData)
        { 
            // url is set to the channel uri in CreateMessageSink
            IpcClientTransportSink sink = new IpcClientTransportSink(url, (IpcClientChannel) channel); 
            if (_prop != null) 
            {
                // Tansfer all properties from the channel to the sink 
                foreach(Object key in _prop.Keys)
                {
                    sink[key] = _prop[key];
                } 
            }
            return sink; 
        } 

        public IClientChannelSinkProvider Next 
        {
            get { return null; }
            set { throw new NotSupportedException(); }
        } 
    } // class IpcClientTransportSinkProvider
 
 

    internal class IpcClientTransportSink : BaseChannelSinkWithProperties, IClientChannelSink 
    {
        // Port cache
        private ConnectionCache portCache = new ConnectionCache();
 
        private IpcClientChannel _channel = null;
 
        // port name 
        private String _portName;
        private const String TokenImpersonationLevelKey = "tokenimpersonationlevel"; 
        private bool authSet = false;
        private const String ConnectionTimeoutKey = "connectiontimeout";
        private TokenImpersonationLevel _tokenImpersonationLevel = TokenImpersonationLevel.Identification;
        private int _timeout = 1000; // Default is one second 
        private static ICollection s_keySet = null;
 
        internal IpcClientTransportSink(String channelURI, IpcClientChannel channel) 
        {
            String objectURI; 
            _channel = channel;
            // Parse the URI
            String simpleChannelUri = IpcChannelHelper.ParseURL(channelURI, out objectURI);
            // extract machine name and port 
            int start = simpleChannelUri.IndexOf("://");
            start += 3; 
 
            _portName = simpleChannelUri.Substring(start);;
        } // IpcClientTransportSink 

        internal ConnectionCache Cache { get { return portCache; } }

        public void ProcessMessage(IMessage msg, 
                                   ITransportHeaders requestHeaders, Stream requestStream,
                                   out ITransportHeaders responseHeaders, out Stream responseStream) 
        { 
            InternalRemotingServices.RemotingTrace("IpcClientChannel::ProcessMessage");
            IpcPort port = null; 

            // the call to SendRequest can block a func eval, so we want to notify the debugger that we're
            // about to call a blocking operation.
            System.Diagnostics.Debugger.NotifyOfCrossThreadDependency(); 

            // The authentication config entries are only valid if secure is true 
            if (authSet && ! _channel.IsSecured) 
                throw new RemotingException(CoreChannel.GetResourceString(
                                                "Remoting_Ipc_AuthenticationConfig")); 

            port = portCache.GetConnection(_portName, _channel.IsSecured, _tokenImpersonationLevel, _timeout);

            IMethodCallMessage mcm = (IMethodCallMessage)msg; 
            int requestLength = (int)requestStream.Length;
 
            Stream ipcStream = new PipeStream(port); 
            IpcClientHandler handler = new IpcClientHandler(port, ipcStream, this);
            handler.SendRequest(msg, requestHeaders, requestStream); 
            responseHeaders = handler.ReadHeaders();
            responseStream = handler.GetResponseStream();

            // The client port will be returned to the cache 
            //   when the response stream is closed.
 
        } // ProcessMessage 

        private IClientChannelSinkStack AsyncProcessMessage(IMessage msg, 
                                   ITransportHeaders requestHeaders, Stream requestStream,
                                   out ITransportHeaders responseHeaders, out Stream responseStream,
                                   IClientChannelSinkStack sinkStack)
        { 
            ProcessMessage(msg, requestHeaders, requestStream, out responseHeaders, out responseStream);
            return sinkStack; 
        } 

        public void AsyncProcessRequest(IClientChannelSinkStack sinkStack, IMessage msg, 
                                        ITransportHeaders headers, Stream requestStream)
        {
            InternalRemotingServices.RemotingTrace("IpcClientTransportSink::AsyncProcessRequest");
            ITransportHeaders responseHeaders; 
            Stream responseStream;
            // Invoke ProcessMessage asynchronously. This should be improved 
            // by using Datagram message 
            AsyncCallback callback = new AsyncCallback(this.AsyncFinishedCallback);
            AsyncMessageDelegate async = new AsyncMessageDelegate(this.AsyncProcessMessage); 
            async.BeginInvoke(msg, headers, requestStream , out responseHeaders,
                                                         out responseStream, sinkStack, callback, null);
        } // AsyncProcessRequest
 
        private void AsyncFinishedCallback(IAsyncResult ar)
        { 
            IClientChannelSinkStack sinkStack = null; 
            try
            { 
                AsyncMessageDelegate d = (AsyncMessageDelegate)(((AsyncResult)ar).AsyncDelegate);
                ITransportHeaders responseHeaders;
                Stream responseStream;
                sinkStack = d.EndInvoke(out responseHeaders, out responseStream, ar); 
                // call down the sink chain
                sinkStack.AsyncProcessResponse(responseHeaders, responseStream); 
            } 
            catch (Exception e)
            { 
                try
                {
                    if (sinkStack != null)
                        sinkStack.DispatchException(e); 
                }
                catch 
                { 
                    // Fatal Error.. ignore
                } 
            }

        }
 
        public void AsyncProcessResponse(IClientResponseChannelSinkStack sinkStack, Object state,
                                         ITransportHeaders headers, Stream stream) 
        { 
            // We don't have to implement this since we are always last in the chain.
            throw new NotSupportedException(); 
        } // AsyncProcessRequest


 
        public Stream GetRequestStream(IMessage msg, ITransportHeaders headers)
        { 
            // Currently, we require a memory stream be handed to us since we need 
            //   the length before sending.
            return null; 
        } // GetRequestStream


        public IClientChannelSink NextChannelSink 
        {
            get { return null; } 
        } // Next 

 

        //
        // Properties
        // 
        public override Object this[Object key]
        { 
            get 
            {
                String keyStr = key as String; 
                if (keyStr == null)
                    return null;

                switch (keyStr.ToLower(CultureInfo.InvariantCulture)) 
                {
                    case TokenImpersonationLevelKey: return _tokenImpersonationLevel.ToString(); 
                    case ConnectionTimeoutKey: return _timeout; 
                    default:
                        break; 
                } // switch (keyStr.ToLower(CultureInfo.InvariantCulture))

                return null;
            } 

            set 
            { 
                String keyStr = key as String;
                if (keyStr == null) 
                    return;

                switch (keyStr.ToLower(CultureInfo.InvariantCulture))
                { 
                    case TokenImpersonationLevelKey: _tokenImpersonationLevel = (TokenImpersonationLevel)(value is TokenImpersonationLevel ? value :
                                                                                            Enum.Parse(typeof(TokenImpersonationLevel), 
                                                                                               (String)value, true)); 
                                                     authSet = true;
                          break; 
                    case ConnectionTimeoutKey: _timeout = Convert.ToInt32(value, CultureInfo.InvariantCulture);
                          break;
                    default:
                          break; 
                } // switch (keyStr.ToLower(CultureInfo.InvariantCulturey))
            } 
        } // this[] 

 
        public override ICollection Keys
        {
            get
            { 
                if (s_keySet == null)
                { 
                    // Don't need to synchronize. Doesn't matter if the list gets 
                    // generated twice.
                } 

                return s_keySet;
            }
        } // Keys 

        // 
        // end of Properties 
        //
 
    } // class IpcClientTransportSink


} // namespace namespace System.Runtime.Remoting.Channels.Ipc 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 
//============================================================================
//  File:       IpcClientChannel.cs 
//  Author:   [....]@Microsoft.Com 
//  Summary:    Implements a channel that transmits method calls over Ipc.
// 
//=========================================================================

using System;
using System.Collections; 
using System.IO;
using System.Runtime.Remoting; 
using System.Runtime.Remoting.Channels; 
using System.Runtime.Remoting.Messaging;
using System.Runtime.InteropServices; 
using System.Security.Principal;
using System.Threading;
using System.Text;
using System.Globalization; 
using System.Security.Permissions;
 
 
namespace System.Runtime.Remoting.Channels.Ipc
{ 
    internal delegate IClientChannelSinkStack AsyncMessageDelegate(IMessage msg,
                                                               ITransportHeaders requestHeaders, Stream requestStream,
                                                               out ITransportHeaders responseHeaders, out Stream responseStream,
                                                               IClientChannelSinkStack sinkStack); 

    public class IpcClientChannel : IChannelSender, ISecurableChannel 
    { 
        private int    _channelPriority = 1;  // channel priority
        private String _channelName = "ipc client"; // channel name 
        private bool _secure = false; // default is unsecure
        private IDictionary _prop = null;

        private IClientChannelSinkProvider _sinkProvider = null; // sink chain provider 

 
        public IpcClientChannel() 
        {
            SetupChannel(); 
        } // IpcClientChannel


        public IpcClientChannel(String name, IClientChannelSinkProvider sinkProvider) 
        {
            _channelName = name; 
            _sinkProvider = sinkProvider; 

            SetupChannel(); 
        }


        // constructor used by config file 
        public IpcClientChannel(IDictionary properties, IClientChannelSinkProvider sinkProvider)
        { 
            if (properties != null) 
            {
                _prop = properties; 
                foreach (DictionaryEntry entry in properties)
                {
                    switch ((String)entry.Key)
                    { 
                    case "name": _channelName = (String)entry.Value; break;
                    case "priority": _channelPriority = Convert.ToInt32(entry.Value, CultureInfo.InvariantCulture); break; 
                    case "secure": _secure = Convert.ToBoolean(entry.Value, CultureInfo.InvariantCulture); break; 
                    default:
                         break; 
                    }
                }
            }
 
            _sinkProvider = sinkProvider;
 
            SetupChannel(); 
        } // IpcClientChannel
 

        private void SetupChannel()
        {
            if (_sinkProvider != null) 
            {
                CoreChannel.AppendProviderToClientProviderChain( 
                    _sinkProvider, new IpcClientTransportSinkProvider(_prop)); 
            }
            else 
                _sinkProvider = CreateDefaultClientProviderChain();
        } // SetupChannel

 
        //
        // ISecurableChannel implementation 
        // 
        public bool IsSecured
        { 
            [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure, Infrastructure=true)]
            get { return _secure; }
            [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure, Infrastructure=true)]
            set { _secure = value; } 
        }
 
        // 
        // IChannel implementation
        // 

        public int ChannelPriority
        {
            [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure, Infrastructure=true)] 
            get { return _channelPriority; }
        } 
 
        public String ChannelName
        { 
            [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure, Infrastructure=true)]
            get { return _channelName; }
        }
 
        // returns channelURI and places object uri into out parameter
        [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure, Infrastructure=true)] 
        public String Parse(String url, out String objectURI) 
        {
            return IpcChannelHelper.ParseURL(url, out objectURI); 
        } // Parse

        //
        // end of IChannel implementation 
        //
 
 

        // 
        // IChannelSender implementation
        //

        [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure, Infrastructure=true)] 
        public virtual IMessageSink CreateMessageSink(String url, Object remoteChannelData, out String objectURI)
        { 
            // Set the out parameters 
            objectURI = null;
            String channelURI = null; 


            if (url != null) // Is this a well known object?
            { 
                // Parse returns null if this is not one of our url's
                channelURI = Parse(url, out objectURI); 
            } 
            else // determine if we want to connect based on the channel data
            { 
                if (remoteChannelData != null)
                {
                    if (remoteChannelData is IChannelDataStore)
                    { 
                        IChannelDataStore cds = (IChannelDataStore)remoteChannelData;
 
                        // see if this is an Ipc uri 
                        String simpleChannelUri = Parse(cds.ChannelUris[0], out objectURI);
                        if (simpleChannelUri != null) 
                            channelURI = cds.ChannelUris[0];
                    }
                }
            } 

            if (null != channelURI) 
            { 
                if (url == null)
                    url = channelURI; 

                IClientChannelSink sink = _sinkProvider.CreateSink(this, url, remoteChannelData);

                // return sink after making sure that it implements IMessageSink 
                IMessageSink msgSink = sink as IMessageSink;
                if ((sink != null) && (msgSink == null)) 
                { 
                    throw new RemotingException(
                        CoreChannel.GetResourceString( 
                            "Remoting_Channels_ChannelSinkNotMsgSink"));
                }

                return msgSink; 
            }
 
            return null; 
        } // CreateMessageSink
 

        //
        // end of IChannelSender implementation
        // 

        private IClientChannelSinkProvider CreateDefaultClientProviderChain() 
        { 
            IClientChannelSinkProvider chain = new BinaryClientFormatterSinkProvider();
            IClientChannelSinkProvider sink = chain; 

            sink.Next = new IpcClientTransportSinkProvider( _prop);

            return chain; 
        } // CreateDefaultClientProviderChain
 
    } // class IpcClientChannel 

 


    internal class IpcClientTransportSinkProvider : IClientChannelSinkProvider
    { 
        IDictionary _prop = null;
        internal IpcClientTransportSinkProvider(IDictionary properties ) 
        { 
            _prop = properties;
        } 

        public IClientChannelSink CreateSink(IChannelSender channel, String url,
                                             Object remoteChannelData)
        { 
            // url is set to the channel uri in CreateMessageSink
            IpcClientTransportSink sink = new IpcClientTransportSink(url, (IpcClientChannel) channel); 
            if (_prop != null) 
            {
                // Tansfer all properties from the channel to the sink 
                foreach(Object key in _prop.Keys)
                {
                    sink[key] = _prop[key];
                } 
            }
            return sink; 
        } 

        public IClientChannelSinkProvider Next 
        {
            get { return null; }
            set { throw new NotSupportedException(); }
        } 
    } // class IpcClientTransportSinkProvider
 
 

    internal class IpcClientTransportSink : BaseChannelSinkWithProperties, IClientChannelSink 
    {
        // Port cache
        private ConnectionCache portCache = new ConnectionCache();
 
        private IpcClientChannel _channel = null;
 
        // port name 
        private String _portName;
        private const String TokenImpersonationLevelKey = "tokenimpersonationlevel"; 
        private bool authSet = false;
        private const String ConnectionTimeoutKey = "connectiontimeout";
        private TokenImpersonationLevel _tokenImpersonationLevel = TokenImpersonationLevel.Identification;
        private int _timeout = 1000; // Default is one second 
        private static ICollection s_keySet = null;
 
        internal IpcClientTransportSink(String channelURI, IpcClientChannel channel) 
        {
            String objectURI; 
            _channel = channel;
            // Parse the URI
            String simpleChannelUri = IpcChannelHelper.ParseURL(channelURI, out objectURI);
            // extract machine name and port 
            int start = simpleChannelUri.IndexOf("://");
            start += 3; 
 
            _portName = simpleChannelUri.Substring(start);;
        } // IpcClientTransportSink 

        internal ConnectionCache Cache { get { return portCache; } }

        public void ProcessMessage(IMessage msg, 
                                   ITransportHeaders requestHeaders, Stream requestStream,
                                   out ITransportHeaders responseHeaders, out Stream responseStream) 
        { 
            InternalRemotingServices.RemotingTrace("IpcClientChannel::ProcessMessage");
            IpcPort port = null; 

            // the call to SendRequest can block a func eval, so we want to notify the debugger that we're
            // about to call a blocking operation.
            System.Diagnostics.Debugger.NotifyOfCrossThreadDependency(); 

            // The authentication config entries are only valid if secure is true 
            if (authSet && ! _channel.IsSecured) 
                throw new RemotingException(CoreChannel.GetResourceString(
                                                "Remoting_Ipc_AuthenticationConfig")); 

            port = portCache.GetConnection(_portName, _channel.IsSecured, _tokenImpersonationLevel, _timeout);

            IMethodCallMessage mcm = (IMethodCallMessage)msg; 
            int requestLength = (int)requestStream.Length;
 
            Stream ipcStream = new PipeStream(port); 
            IpcClientHandler handler = new IpcClientHandler(port, ipcStream, this);
            handler.SendRequest(msg, requestHeaders, requestStream); 
            responseHeaders = handler.ReadHeaders();
            responseStream = handler.GetResponseStream();

            // The client port will be returned to the cache 
            //   when the response stream is closed.
 
        } // ProcessMessage 

        private IClientChannelSinkStack AsyncProcessMessage(IMessage msg, 
                                   ITransportHeaders requestHeaders, Stream requestStream,
                                   out ITransportHeaders responseHeaders, out Stream responseStream,
                                   IClientChannelSinkStack sinkStack)
        { 
            ProcessMessage(msg, requestHeaders, requestStream, out responseHeaders, out responseStream);
            return sinkStack; 
        } 

        public void AsyncProcessRequest(IClientChannelSinkStack sinkStack, IMessage msg, 
                                        ITransportHeaders headers, Stream requestStream)
        {
            InternalRemotingServices.RemotingTrace("IpcClientTransportSink::AsyncProcessRequest");
            ITransportHeaders responseHeaders; 
            Stream responseStream;
            // Invoke ProcessMessage asynchronously. This should be improved 
            // by using Datagram message 
            AsyncCallback callback = new AsyncCallback(this.AsyncFinishedCallback);
            AsyncMessageDelegate async = new AsyncMessageDelegate(this.AsyncProcessMessage); 
            async.BeginInvoke(msg, headers, requestStream , out responseHeaders,
                                                         out responseStream, sinkStack, callback, null);
        } // AsyncProcessRequest
 
        private void AsyncFinishedCallback(IAsyncResult ar)
        { 
            IClientChannelSinkStack sinkStack = null; 
            try
            { 
                AsyncMessageDelegate d = (AsyncMessageDelegate)(((AsyncResult)ar).AsyncDelegate);
                ITransportHeaders responseHeaders;
                Stream responseStream;
                sinkStack = d.EndInvoke(out responseHeaders, out responseStream, ar); 
                // call down the sink chain
                sinkStack.AsyncProcessResponse(responseHeaders, responseStream); 
            } 
            catch (Exception e)
            { 
                try
                {
                    if (sinkStack != null)
                        sinkStack.DispatchException(e); 
                }
                catch 
                { 
                    // Fatal Error.. ignore
                } 
            }

        }
 
        public void AsyncProcessResponse(IClientResponseChannelSinkStack sinkStack, Object state,
                                         ITransportHeaders headers, Stream stream) 
        { 
            // We don't have to implement this since we are always last in the chain.
            throw new NotSupportedException(); 
        } // AsyncProcessRequest


 
        public Stream GetRequestStream(IMessage msg, ITransportHeaders headers)
        { 
            // Currently, we require a memory stream be handed to us since we need 
            //   the length before sending.
            return null; 
        } // GetRequestStream


        public IClientChannelSink NextChannelSink 
        {
            get { return null; } 
        } // Next 

 

        //
        // Properties
        // 
        public override Object this[Object key]
        { 
            get 
            {
                String keyStr = key as String; 
                if (keyStr == null)
                    return null;

                switch (keyStr.ToLower(CultureInfo.InvariantCulture)) 
                {
                    case TokenImpersonationLevelKey: return _tokenImpersonationLevel.ToString(); 
                    case ConnectionTimeoutKey: return _timeout; 
                    default:
                        break; 
                } // switch (keyStr.ToLower(CultureInfo.InvariantCulture))

                return null;
            } 

            set 
            { 
                String keyStr = key as String;
                if (keyStr == null) 
                    return;

                switch (keyStr.ToLower(CultureInfo.InvariantCulture))
                { 
                    case TokenImpersonationLevelKey: _tokenImpersonationLevel = (TokenImpersonationLevel)(value is TokenImpersonationLevel ? value :
                                                                                            Enum.Parse(typeof(TokenImpersonationLevel), 
                                                                                               (String)value, true)); 
                                                     authSet = true;
                          break; 
                    case ConnectionTimeoutKey: _timeout = Convert.ToInt32(value, CultureInfo.InvariantCulture);
                          break;
                    default:
                          break; 
                } // switch (keyStr.ToLower(CultureInfo.InvariantCulturey))
            } 
        } // this[] 

 
        public override ICollection Keys
        {
            get
            { 
                if (s_keySet == null)
                { 
                    // Don't need to synchronize. Doesn't matter if the list gets 
                    // generated twice.
                } 

                return s_keySet;
            }
        } // Keys 

        // 
        // end of Properties 
        //
 
    } // class IpcClientTransportSink


} // namespace namespace System.Runtime.Remoting.Channels.Ipc 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
